"""
ADAM Model Module: Advanced Dissolution, Absorption, and Metabolism Model

This module implements a comprehensive absorption model based on the provided code structure
with enhanced validation, mass conservation, and parameter management.

Key Features:
- Regional intestinal absorption modeling with Region enum
- Enhanced parameter validation and error handling
- Mass conservation validation
- Custom initial distribution support
- Comprehensive logging and warnings

Author: BlackCat@CPPO
Version: 3.0.0
"""

import numpy as np
import warnings
import logging
from enum import Enum
from typing import Dict, Any, List, Optional, Union
from scipy.integrate import solve_ivp
from dataclasses import dataclass

# ------------------------------ 常量定义 ------------------------------
@dataclass
class RegionalParams:
    """区域参数类（每个胃肠道区域的物理属性）"""
    pH: float
    volume: float       # 区域体积（cm³）
    transit_time: float # 药物停留时间（秒）
    surface_area: float # 表面积（cm²）
    blood_flow: float   # 血流量（mL/min）
    absorption_rate: float # 吸收速率常数（1/s）
    permeability_factor: float # 黏膜渗透性系数

@dataclass
class ModelParams:
    """全局模型参数类（跨区域的共享参数）"""
    solubility: float           # 药物溶解度（mg/mL）
    permeability: float         # 黏膜渗透性（cm/s）
    mass_transfer_coeff: float  # 溶解传质系数（cm/s）

class Region(Enum):
    """胃肠道区域枚举（通过名称而非索引访问，提高可读性）"""
    STOMACH = "stomach"
    DUODENUM = "duodenum"
    JEJUNUM_1 = "jejunum_1"
    JEJUNUM_2 = "jejunum_2"
    ILEUM_1 = "ileum_1"
    ILEUM_2 = "ileum_2"
    ILEUM_3 = "ileum_3"
    COLON = "colon"

class Constants:
    """全局常量（替代魔法数值，提高可维护性）"""
    MIN_DOSE = 0.1          # 最小有效剂量（mg）
    MAX_DOSE = 1000.0       # 最大有效剂量（mg）
    MIN_SOLUBILITY = 0.001  # 最小溶解度（mg/mL）
    MAX_SOLUBILITY = 100.0  # 最大溶解度（mg/mL）
    MIN_PERMEABILITY = 1e-8 # 最小渗透性（cm/s）
    MAX_PERMEABILITY = 1e-2 # 最大渗透性（cm/s）
    DEFAULT_TOTAL_TIME = 24 # 默认模拟总时间（小时）
    MASS_DEV_THRESHOLD = 0.1 # 质量守恒最大允许偏差（初始剂量的10%）
    SOLID_MIN = 0.1         # 固体量最小阈值（mg）

# ------------------------------ 辅助函数 ------------------------------
def validate_time_points(time_points: np.ndarray) -> np.ndarray:
    """验证并调整时间点数组，确保严格递增且至少有2个点"""
    original_length = len(time_points)
    time_points = np.asarray(time_points, dtype=float)
    
    if len(time_points) < 2:
        warnings.warn(f"时间点数量不足（当前{original_length}），使用默认[0, {Constants.DEFAULT_TOTAL_TIME}]（25点）")
        return np.linspace(0, Constants.DEFAULT_TOTAL_TIME, 25)
    
    # 确保严格递增
    if not np.all(np.diff(time_points) > 0):
        unique_points = np.unique(time_points)
        if len(unique_points) < 2:
            warnings.warn("去重后时间点仍不足，使用默认时间点")
            return np.linspace(0, Constants.DEFAULT_TOTAL_TIME, 25)
        warnings.warn(f"时间点非递增，调整为唯一值：{unique_points}")
        return unique_points
    
    if len(time_points) != original_length:
        warnings.warn(f"时间点从{original_length}调整为{len(time_points)}（去重后）")
    
    return time_points

def validate_parameters(params: Dict[str, Any]) -> None:
    """校验所有参数在合理范围内"""
    # 剂量相关
    params['dose'] = max(min(params.get('dose', Constants.MIN_DOSE), Constants.MAX_DOSE), Constants.MIN_DOSE)
    
    # 溶解度相关
    params['solubility'] = max(min(params.get('solubility', 1.0), Constants.MAX_SOLUBILITY), Constants.MIN_SOLUBILITY)
    
    # 渗透性相关
    params['permeability'] = max(min(params.get('permeability', 1e-4), Constants.MAX_PERMEABILITY), Constants.MIN_PERMEABILITY)
    
    # 其他参数（示例，根据实际模型扩展）
    if 'particle_size' in params:
        params['particle_size'] = max(params['particle_size'], 0.1)  # 粒径≥0.1μm
    if 'diffusion_coefficient' in params:
        params['diffusion_coefficient'] = max(params['diffusion_coefficient'], 0)  # 扩散系数≥0

def validate_initial_distribution(
    regions: List[Region],
    initial_distribution: Optional[Dict[Region, float]],
    total_dose: float
) -> List[float]:
    """验证并处理自定义初始分布（按区域名称）"""
    n_regions = len(regions)
    
    # 默认：所有剂量分配到第一个区域（胃）
    initial_solid = [0.0] * n_regions
    initial_solid[0] = max(total_dose, Constants.SOLID_MIN)
    
    if not initial_distribution:
        return initial_solid
    
    # 处理自定义分布
    region_names = [r.value for r in regions]
    custom_dist = {}
    
    for region, amount in initial_distribution.items():
        if isinstance(region, Region):
            region_name = region.value
        else:
            region_name = str(region)
        
        if region_name in region_names:
            custom_dist[region_name] = amount
        else:
            warnings.warn(f"忽略无效区域: {region}")
    
    if not custom_dist:
        return initial_solid
    
    total_custom = sum(custom_dist.values())
    if total_custom <= 0:
        return initial_solid
    
    # 缩放至总剂量
    scale_factor = total_dose / total_custom
    initial_solid = [0.0] * n_regions
    
    for i, region in enumerate(regions):
        amount = custom_dist.get(region.value, 0.0) * scale_factor
        initial_solid[i] = max(amount, Constants.SOLID_MIN)
    
    return initial_solid

# ------------------------------ 主类 ------------------------------
class ADAMAbsorptionModel:
    # 类属性：允许的参数列表
    allowed_params = {
        'dose', 'solubility', 'permeability', 'molecular_weight', 'pKa', 'logP',
        'particle_size', 'density', 'intrinsic_solubility', 'diffusion_coefficient',
        'boundary_layer', 'surface_area', 'fraction_unbound', 'intrinsic_clearance',
        'fa', 'fg', 'fh', 'initial_distribution', 'region_weights',
        'CL_hepatic', 'CL_renal', 'CL_biliary', 'CL_other', 'Vss', 'BP', 'fu'
    }
    
    def __init__(self, regions: List[Region] = None, default_params: Dict[str, Any] = None):
        """
        初始化ADAM吸收模型
        
        参数:
            regions: 胃肠道区域列表（默认使用所有8个区域）
            default_params: 默认参数（如分子量、解离常数等）
        """
        self.regions = regions or list(Region)
        self.params = default_params or {}
        self.logger = logging.getLogger(self.__class__.__name__)
        logging.basicConfig(level=logging.INFO)

        # 初始化全局模型参数
        self.model_params = self._setup_global_parameters()
        # 设置默认区域参数
        self.regional_params = self._setup_regional_parameters()

    def _setup_global_parameters(self) -> ModelParams:
        """设置全局模型参数（溶解度、渗透性等）"""
        return ModelParams(
            solubility=1.0,  # 溶解度（mg/mL）
            permeability=1e-4,  # 黏膜渗透性（cm/s）
            mass_transfer_coeff=0.5  # 传质系数（cm/s）
        )

    def _setup_regional_parameters(self) -> Dict[Region, RegionalParams]:
        """设置各区域的生理参数"""
        return {
            Region.STOMACH: RegionalParams(
                pH=1.5, volume=250.0, transit_time=0.5, surface_area=0.1,
                blood_flow=0.3, absorption_rate=0.01, permeability_factor=0.1
            ),
            Region.DUODENUM: RegionalParams(
                pH=6.0, volume=50.0, transit_time=0.25, surface_area=0.3,
                blood_flow=1.0, absorption_rate=0.8, permeability_factor=1.0
            ),
            Region.JEJUNUM_1: RegionalParams(
                pH=6.5, volume=60.0, transit_time=0.5, surface_area=0.4,
                blood_flow=1.2, absorption_rate=0.9, permeability_factor=1.1
            ),
            Region.JEJUNUM_2: RegionalParams(
                pH=6.8, volume=70.0, transit_time=0.75, surface_area=0.5,
                blood_flow=1.1, absorption_rate=0.85, permeability_factor=1.0
            ),
            Region.ILEUM_1: RegionalParams(
                pH=7.2, volume=80.0, transit_time=1.0, surface_area=0.6,
                blood_flow=0.9, absorption_rate=0.7, permeability_factor=0.9
            ),
            Region.ILEUM_2: RegionalParams(
                pH=7.4, volume=90.0, transit_time=1.25, surface_area=0.7,
                blood_flow=0.8, absorption_rate=0.6, permeability_factor=0.8
            ),
            Region.ILEUM_3: RegionalParams(
                pH=7.5, volume=100.0, transit_time=1.5, surface_area=0.8,
                blood_flow=0.7, absorption_rate=0.5, permeability_factor=0.7
            ),
            Region.COLON: RegionalParams(
                pH=7.0, volume=150.0, transit_time=12.0, surface_area=0.2,
                blood_flow=0.4, absorption_rate=0.2, permeability_factor=0.3
            )
        }

    def _adam_odes(self, y: np.ndarray) -> np.ndarray:
        """
        ADAM模型ODE系统
        
        状态变量:
            y[0:n_regions]: 各区域固体药物量
            y[n_regions:2*n_regions]: 各区域溶解药物量
        """
        n_regions = len(self.regions)
        
        # 校验状态向量维度
        if len(y) != 2 * n_regions:
            raise ValueError(f"状态向量维度错误：预期{2 * n_regions}维，实际{len(y)}维")
        
        # 拆分状态变量
        solid_amounts = y[:n_regions]       # 各区域固体药量（g）
        dissolved_amounts = y[n_regions:]   # 各区域溶解药量（g）
        
        # 初始化导数数组
        d_solid_dt = np.zeros(n_regions)
        d_dissolved_dt = np.zeros(n_regions)
        
        # ------------------------------
        # 步骤1：计算各区域的转运速率（单位：1/s）
        # 转运速率 = 1/停留时间（避免除零），限制最大转运速率为10/s（防止过快的转运）
        # ------------------------------
        transit_rates = []
        for region in self.regions:
            transit_time = self.regional_params[region].transit_time
            transit_time = max(transit_time, 0.01)  # 避免除零（最小停留时间0.01秒）
            transit_rate = 1.0 / transit_time       # 转运速率（1/s）
            transit_rate = min(transit_rate, 10.0)  # 限制最大转运速率（防止数值爆炸）
            transit_rates.append(transit_rate)
        
                # ------------------------------
        # 步骤2：计算各区域的固体与溶解药物动态（质量守恒）
        # ------------------------------
        for i, region in enumerate(self.regions):
            region_param = self.regional_params[region]
            solubility = self.model_params.solubility
            permeability = self.model_params.permeability
            
            # ------------------------------
            # 子步骤2.1：计算溶解速率（基于传质动力学的简化模型）
            # 溶解速率 = 传质系数 × 表面积 × (溶解度 - 当前浓度)（当当前浓度 < 溶解度时）
            # 当前浓度 = 溶解药量 / 区域体积（g/cm³）
            # ------------------------------
            current_conc = dissolved_amounts[i] / max(region_param.volume, 1e-6)  # 避免除零（体积极小）
            concentration_deficit = solubility - current_conc  # 溶解动力（溶解度-当前浓度）
            
            dissolution_rate = self.model_params.mass_transfer_coeff * region_param.surface_area * concentration_deficit
            dissolution_rate = max(dissolution_rate, 0.0)  # 浓度不足时溶解速率为0
            
            # ------------------------------
            # 子步骤2.2：计算吸收速率（基于渗透性的简化模型）
            # 吸收速率 = 渗透性 × 表面积 × 当前浓度（假设间质药物浓度为0）
            # ------------------------------
            absorption_rate = permeability * region_param.surface_area * current_conc
            absorption_rate = max(absorption_rate, 0.0)  # 浓度为负时吸收速率为0
            
            # ------------------------------
            # 子步骤2.3：固体药物动态方程（流入-流出-溶解）
            # 流入：前一个区域的转运量（i=0时无流入）
            # 流出：当前区域的转运量
            # 净变化 = 流入 - 流出 - 溶解量
            # ------------------------------
            inflow_solid = 0.0
            if i > 0:
                inflow_solid = transit_rates[i-1] * solid_amounts[i-1]  # 前区域转运来的固体量（g/s）
            
            outflow_solid = transit_rates[i] * solid_amounts[i]  # 当前区域流出的固体量（g/s）
            
            d_solid_dt[i] = inflow_solid - dissolution_rate - outflow_solid
            
            # ------------------------------
            # 子步骤2.4：溶解药物动态方程（流入-流出-溶解-吸收）
            # 流入：前一个区域的转运量（i=0时无流入）
            # 流出：当前区域的转运量
            # 净变化 = 流入 + 溶解量 - 吸收量 - 流出量
            # ------------------------------
            inflow_dissolved = 0.0
            if i > 0:
                inflow_dissolved = transit_rates[i-1] * dissolved_amounts[i-1]  # 前区域转运来的溶解量（g/s）
            
            outflow_dissolved = transit_rates[i] * dissolved_amounts[i]  # 当前区域流出的溶解量（g/s）
            
            d_dissolved_dt[i] = inflow_dissolved + dissolution_rate - absorption_rate - outflow_dissolved
            
            # ------------------------------
            # 子步骤2.5：数值稳定性保护（限制导数范围）
            # 防止因参数异常导致的导数过大（如传质系数错误设置为1e5）
            # ------------------------------
            d_solid_dt[i] = np.clip(d_solid_dt[i], -1e4, 1e4)  # 更宽松的范围（原100可能过严）
            d_dissolved_dt[i] = np.clip(d_dissolved_dt[i], -1e4, 1e4)
        
        # 合并导数（固体量在前，溶解量在后）
        derivatives = np.concatenate([d_solid_dt, d_dissolved_dt])
        return derivatives

    def _calculate_regional_absorption(self, region: Region, dissolved_conc: float) -> float:
        """计算单个区域的吸收速率"""
        # 示例实现：基于溶解浓度和区域特性
        if dissolved_conc <= 0:
            return 0.0
        
        region_params = self.regional_params[region]
        base_absorption = 0.1 * dissolved_conc * region_params.absorption_rate
        return min(base_absorption, dissolved_conc * 2.0)  # 防止超吸收

    def _simple_absorption_fallback(self, time_points: np.ndarray, params: Dict[str, Any]) -> Dict[str, Any]:
        """备用吸收模型（用于ODE求解失败时）"""
        n_regions = len(self.regions)
        total_dose = params['dose']
        
        # 使用简单的指数衰减模型
        ka = 0.5  # 默认吸收速率
        absorption_rate = total_dose * ka * np.exp(-ka * time_points)
        cumulative_absorption = total_dose * (1 - np.exp(-ka * time_points))
        
        # 创建区域数据
        regional_amounts = {}
        regional_dissolved = {}
        regional_absorbed = {}
        
        # 简单分配：大部分在胃，其余逐渐转移
        for i, region in enumerate(self.regions):
            # 固体量随时间减少
            if i == 0:  # 胃
                solid = total_dose * np.exp(-ka * time_points)
            else:
                solid = np.zeros_like(time_points)
            
            # 溶解量
            dissolved = cumulative_absorption / n_regions
            
            # 吸收速率
            if i == 0:  # 胃
                absorbed = absorption_rate * 0.7
            elif i == 1:  # 十二指肠
                absorbed = absorption_rate * 0.2
            else:  # 其他区域
                absorbed = absorption_rate * 0.1 / (n_regions - 2)
            
            # Handle both Region enum and string cases
            region_key = region.value if hasattr(region, 'value') else str(region)
            regional_amounts[region_key] = solid
            regional_dissolved[region_key] = dissolved
            regional_absorbed[region_key] = absorbed
        
        # 计算生物利用度
        fa = max(min(params.get('fa', 1.0), 1.0), 0.1)
        fg = max(min(params.get('fg', 1.0), 1.0), 0.1)
        fh = max(min(params.get('fh', 1.0), 1.0), 0.1)
        
        final_absorption = cumulative_absorption[-1] if len(cumulative_absorption) > 0 else 0
        absorption_fraction = min(final_absorption / total_dose, 1.0) if total_dose > 0 else 0.0
        bioavailability = absorption_fraction * fa * fg * fh
        bioavailability = max(min(bioavailability, 1.0), 0.01)
        
        return {
            'regional_amounts': regional_amounts,
            'regional_dissolved': regional_dissolved,
            'regional_absorbed': regional_absorbed,
            'total_absorption_rate': absorption_rate,
            'cumulative_absorption': cumulative_absorption,
            'fraction_absorbed': cumulative_absorption / total_dose if total_dose > 0 else np.zeros_like(time_points),
            'bioavailability': bioavailability,
            'time_points': time_points,
            'integration_success': False,
            'mass_conservation_check': {
                'max_deviation': 0.0,
                'initial_dose': total_dose,
                'final_total': total_dose
            }
        }

    def calculate_adam_absorption(
        self, 
        time_points: np.ndarray, 
        individual_params: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        计算综合ADAM吸收过程（增强版）
        
        参数:
            time_points: 时间数组（小时）- 必须严格递增
            individual_params: 个体化参数（键需在allowed_params中）
            
        返回:
            包含吸收结果的字典，含质量守恒验证信息
            
        单位说明:
            - dose: mg
            - solubility: mg/mL
            - permeability: cm/s
            - molecular_weight: g/mol
            - particle_size: μm
            - density: g/cm³
            - time_points: hours
        """
        # -------------------- 步骤1：参数初始化与校验 --------------------
        allowed_params = {
            'dose', 'solubility', 'permeability', 'molecular_weight', 'pKa', 'logP',
            'particle_size', 'density', 'intrinsic_solubility', 'diffusion_coefficient',
            'boundary_layer', 'surface_area', 'fraction_unbound', 'intrinsic_clearance',
            'fa', 'fg', 'fh', 'initial_distribution', 'region_weights',
            'CL_hepatic', 'CL_renal', 'CL_biliary', 'CL_other', 'Vss', 'BP', 'fu'
        }
        
        # 处理个体化参数（过滤非法键）
        individual_params = individual_params if individual_params is not None else {}
        invalid_keys = set(individual_params.keys()) - allowed_params
        if invalid_keys:
            warnings.warn(f"忽略非法参数: {invalid_keys}")
            individual_params = {k: v for k, v in individual_params.items() if k in allowed_params}
        
        # 合并参数
        params = {**self.params}
        for key, value in individual_params.items():
            params[key] = value
        
        # 校验所有参数范围
        validate_parameters(params)
        
        # -------------------- 步骤2：初始条件设置 --------------------
        n_regions = len(self.regions)
        total_dose = params['dose']
        
        # 处理自定义初始分布
        initial_solid = validate_initial_distribution(
            regions=self.regions,
            initial_distribution=individual_params.get('initial_distribution'),
            total_dose=total_dose
        )
        
        # 处理区域权重
        if 'region_weights' in individual_params:
            weights = np.array(individual_params['region_weights'])
            if len(weights) != n_regions:
                raise ValueError(f"region_weights长度需为{n_regions}，实际为{len(weights)}")
            if np.any(weights < 0):
                raise ValueError("region_weights不能包含负数")
            weights = weights / np.sum(weights)
            initial_solid = [max(w * total_dose, Constants.SOLID_MIN) for w in weights]
        
        # 初始化状态向量
        initial_conditions = initial_solid.copy()
        initial_conditions.extend([0.0] * n_regions)  # 初始溶解量为0
        
        # -------------------- 步骤3：时间点处理 --------------------
        time_points = validate_time_points(time_points)
        t_span = [float(time_points[0]), float(time_points[-1])]
        y0 = np.array(initial_conditions, dtype=float)
        
        # 验证状态向量维度
        expected_size = 2 * n_regions
        if len(y0) != expected_size:
            raise ValueError(f"初始状态维度错误（预期{expected_size}，实际{len(y0)}）")
        
        # -------------------- 步骤4：ODE求解 --------------------
        try:
            solution = solve_ivp(
                fun=self._adam_odes,
                t_span=t_span,
                y0=y0,
                t_eval=time_points,
                args=(params,),
                method='RK45', #BDF
            )
            
            # 检查积分是否成功
            if not solution.success:
                warnings.warn(f"ODE积分失败: {solution.message}")
                return self._simple_absorption_fallback(time_points, params)
            
            # 验证解的维度
            if solution.y.shape[0] != expected_size:
                warnings.warn(f"解维度异常（预期{expected_size}，实际{solution.y.shape[0]}）")
                return self._simple_absorption_fallback(time_points, params)
                
        except Exception as e:
            self.logger.error(f"ODE求解错误: {str(e)}", exc_info=True)
            return self._simple_absorption_fallback(time_points, params)
        
        # -------------------- 步骤5：结果提取与验证 --------------------
        try:
            regional_amounts = {}
            regional_dissolved = {}
            regional_absorbed = {}
            
            for i, region in enumerate(self.regions):
                # 提取固体量（前n_regions）
                solid = solution.y[i, :]
                regional_amounts[region.value] = np.clip(solid, 0, total_dose)
                
                # 提取溶解量（后n_regions）
                dissolved = solution.y[i + n_regions, :]
                regional_dissolved[region.value] = np.clip(dissolved, 0, total_dose)
                
                # 计算吸收速率
                absorption_rates = [max(self._calculate_regional_absorption(region, c), 0) 
                                   for c in regional_dissolved[region.value]]
                regional_absorbed[region.value] = np.array(absorption_rates)
            
            # 验证质量守恒
            total_solid = np.sum(list(regional_amounts.values()), axis=0)
            total_dissolved = np.sum(list(regional_dissolved.values()), axis=0)
            total_drug = total_solid + total_dissolved
            max_global_deviation = np.max(np.abs(total_drug - total_dose))
            
            # 累积吸收计算
            dt = np.diff(time_points)
            cumulative_absorption = np.zeros_like(time_points)
            total_absorption_rate = np.sum(list(regional_absorbed.values()), axis=0)
            
            if len(dt) > 0:
                cumulative_absorption[1:] = np.cumsum(0.5 * (total_absorption_rate[:-1] + total_absorption_rate[1:]) * dt)
            
            cumulative_absorption = np.minimum(cumulative_absorption, total_dose)
            
            # 最终缩放
            final_absorption = cumulative_absorption[-1] if len(cumulative_absorption) > 0 else 0
            if final_absorption > total_dose:
                scale_factor = total_dose / final_absorption
                cumulative_absorption *= scale_factor
                total_absorption_rate *= scale_factor
                for region in regional_absorbed:
                    regional_absorbed[region] *= scale_factor
            
            # 计算生物利用度
            fa = max(min(params.get('fa', 1.0), 1.0), 0.1)
            fg = max(min(params.get('fg', 1.0), 1.0), 0.1)
            fh = max(min(params.get('fh', 1.0), 1.0), 0.1)
            absorption_fraction = min(final_absorption / total_dose, 1.0) if total_dose > 0 else 0.0
            bioavailability = absorption_fraction * fa * fg * fh
            bioavailability = max(min(bioavailability, 1.0), 0.01)
            
            # -------------------- 步骤6：返回结果 --------------------
            return {
                'regional_amounts': regional_amounts,
                'regional_dissolved': regional_dissolved,
                'regional_absorbed': regional_absorbed,
                'total_absorption_rate': total_absorption_rate,
                'cumulative_absorption': cumulative_absorption,
                'fraction_absorbed': cumulative_absorption / total_dose if total_dose > 0 else np.zeros_like(time_points),
                'bioavailability': bioavailability,
                'time_points': time_points,
                'integration_success': True,
                'mass_conservation_check': {
                    'max_deviation': max_global_deviation,
                    'initial_dose': total_dose,
                    'final_total': total_drug[-1] if len(total_drug) > 0 else 0
                }
            }
            
        except (IndexError, KeyError) as e:
            self.logger.error(f"结果提取错误: {str(e)}", exc_info=True)
            return self._simple_absorption_fallback(time_points, params)
        except Exception as e:
            self.logger.error(f"未知错误: {str(e)}", exc_info=True)
            return self._simple_absorption_fallback(time_points, params)

# ------------------------------ 向后兼容类 ------------------------------
class ADAMModel:
    """
    向后兼容类，使用新的ADAMAbsorptionModel实现
    """
    def __init__(self, parameters: Dict[str, Any]):
        """
        初始化ADAM模型（向后兼容）
        
        参数:
            parameters: 模型参数字典
        """
        self.params = parameters
        self.regions = [
            Region.STOMACH, Region.DUODENUM, Region.JEJUNUM_1, Region.JEJUNUM_2,
            Region.ILEUM_1, Region.ILEUM_2, Region.ILEUM_3, Region.COLON
        ]
        self.model = ADAMAbsorptionModel(self.regions, parameters)
        
        # 设置区域参数（向后兼容）
        self.regional_params = self.model.regional_params

    def calculate_adam_absorption(self, time_points: np.ndarray, individual_params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """向后兼容方法"""
        # 转换参数格式（从字符串到Region枚举）
        if individual_params and 'initial_distribution' in individual_params:
            dist = individual_params['initial_distribution']
            if isinstance(dist, dict) and all(isinstance(k, str) for k in dist.keys()):
                new_dist = {}
                for k, v in dist.items():
                    try:
                        new_dist[Region(k)] = v
                    except ValueError:
                        new_dist[k] = v
                individual_params['initial_distribution'] = new_dist
        
        result = self.model.calculate_adam_absorption(time_points, individual_params)
        
        # 转换回字符串键（向后兼容）
        return result

    def _simple_absorption_fallback(self, time_points: np.ndarray, params: Dict[str, Any]) -> Dict[str, Any]:
        """向后兼容方法"""
        return self.model._simple_absorption_fallback(time_points, params)

    def _adam_odes(self, t, y, params):
        """向后兼容方法"""
        return self.model._adam_odes(t, y, params)

# ------------------------------ 快捷函数 ------------------------------
def create_adam_model(parameters: Dict[str, Any]) -> ADAMModel:
    """创建ADAM模型的快捷函数"""
    return ADAMModel(parameters)

def calculate_absorption(time_points: np.ndarray, parameters: Dict[str, Any], individual_params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
    """计算吸收的快捷函数"""
    model = ADAMModel(parameters)
    return model.calculate_adam_absorption(time_points, individual_params)